package com.tianji.learning.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.tianji.common.utils.StringUtils;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.DelayQueue;


/**
 * 学习记录延迟任务
 */
@Slf4j
@Component
public class LearningRecordDelayTask {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private LearningRecordMapper recordMapper;

    @Autowired
    private LearningLessonMapper learningLessonMapper;


    private final static String KEY = "learning:record:key:{}";

    private final DelayQueue<DelayTask<LearningRecordInfo>> delayTasks = new DelayQueue<>();

    @PostConstruct
    public void init() {
//        new Thread(this::consumeDelayTasks).start();
        CompletableFuture.runAsync(()->consumeDelayTasks());
    }




    public void consumeDelayTasks() {

        while (true) {
            //2、获取延迟任务中数据
            try {
                DelayTask<LearningRecordInfo> delayTask = delayTasks.take();
                LearningRecordInfo data = delayTask.getData();
                //3、查询redis中的数据
                LearningRecordFormDTO formDTO = new LearningRecordFormDTO();
                formDTO.setLessonId(data.getLessonId());
                formDTO.setSectionId(data.getSectionId());
                LearningRecord learningRecord = readLearningRecordCache(formDTO);
                if (ObjectUtil.isEmpty(learningRecord) || ObjectUtil.isEmpty(learningRecord.getMoment()) || !ObjectUtil.equals(data.getMoment(),learningRecord.getMoment())){
                    continue;
                }

                //4、更新学习记录
                learningRecord.setFinished(null);
                recordMapper.updateById(learningRecord);

                //5、更新课表
                LearningLesson learningLesson = new LearningLesson();
                learningLesson.setLatestLearnTime(LocalDateTime.now().minusSeconds(20));
                learningLesson.setId(data.getLessonId());
                learningLesson.setLatestSectionId(data.getSectionId());
                learningLessonMapper.updateById(learningLesson);
            } catch (InterruptedException e) {
                log.error("执行播放进度延时检测任务失败！！！，原因：{}",e);
            }
        }
    }

    /**
     * 读取缓存中的学习记录信息
     *
     * @param learningRecordFormDTO 表单数据
     * @return 学习记录
     */
    public LearningRecord readLearningRecordCache(LearningRecordFormDTO learningRecordFormDTO) {
        //1、尝试从redis缓存中取出学习记录信息
        Object hashValue = redisTemplate.opsForHash().get(StringUtils.format(KEY,learningRecordFormDTO.getLessonId()), String.valueOf(learningRecordFormDTO.getSectionId()));

        LearningRecord learningRecord = new LearningRecord();

        if (ObjectUtil.isEmpty(hashValue)) {
            //1.1、如果为空去数据库中查询学习记录信息
            LambdaQueryWrapper<LearningRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LearningRecord::getLessonId, learningRecordFormDTO.getLessonId())
                    .eq(LearningRecord::getSectionId, learningRecordFormDTO.getSectionId());

            LearningRecord record = recordMapper.selectOne(queryWrapper);

            //1.2、如果数据库也没有则返回空;
            if (ObjectUtil.isEmpty(record)) {
                log.error("数据库中不存在该数据，LessonID：{}，SectionID：{}", learningRecordFormDTO.getLessonId(), learningRecordFormDTO.getSectionId());
                return null;
            }

            //1.3、存入redis
            LearningRecordCache learningRecordCache = new LearningRecordCache(record);
            redisTemplate.opsForHash().put(StringUtils.format(KEY,String.valueOf(record.getLessonId())), String.valueOf(record.getSectionId()), JSONUtil.toJsonStr(learningRecordCache));
            redisTemplate.expire(KEY + record.getLessonId(), Duration.ofSeconds(60));

            return record;

        }

        //2、解析hashValue，并封装结果集
        LearningRecord learningRecordCache = JSONUtil.toBean(String.valueOf(hashValue),LearningRecord.class);
        learningRecord.setId(learningRecordCache.getId());
        learningRecord.setFinished(learningRecordCache.getFinished());
        learningRecord.setMoment(learningRecordCache.getMoment());
        learningRecord.setLessonId(learningRecordFormDTO.getLessonId());
        learningRecord.setSectionId(learningRecordFormDTO.getSectionId());

        return learningRecord;
    }


    /**
     * 将学习记录写入缓存
     *
     * @param oldRecord
     */
    public void writeLearningRecordCache(LearningRecord oldRecord) {
        //1、将记录写入缓存
        LearningRecordCache learningRecordCache = new LearningRecordCache(oldRecord);
        redisTemplate.opsForHash().put(StringUtils.format(KEY,oldRecord.getLessonId()), String.valueOf(oldRecord.getSectionId()), JSONUtil.toJsonStr(learningRecordCache));
        redisTemplate.expire(KEY + oldRecord.getLessonId(), Duration.ofSeconds(60));

        //2、将任务加入延时队列
        LearningRecordInfo learningRecordInfo = new LearningRecordInfo(oldRecord);

        DelayTask<LearningRecordInfo> delayTask = new DelayTask<LearningRecordInfo>(learningRecordInfo, Duration.ofSeconds(20));
        delayTasks.add(delayTask);
    }

    /**
     * 清除缓存中学习记录
     *
     * @param oldRecord
     */
    public void cleanLearningRecordCache(LearningRecord oldRecord) {
        //删除缓存记录
        redisTemplate.opsForHash().delete(StringUtils.format(KEY,oldRecord.getLessonId()), String.valueOf(oldRecord.getSectionId()));
    }

    @Data
    static
    class LearningRecordCache {
        private Long id;     //学习记录的id

        private Integer moment; //视频的当前观看时间点，单位秒

        private Boolean finished; //是否完成学习，默认false

        LearningRecordCache(LearningRecord learningRecord) {
            this.id = learningRecord.getId();
            this.finished = learningRecord.getFinished();
            this.moment = learningRecord.getMoment();
        }
    }

    @Data
    static
    class LearningRecordInfo {
        private Long id;     //学习记录的id

        private Integer moment; //视频的当前观看时间点，单位秒

        private Boolean finished; //是否完成学习，默认false

        private Long lessonId;

        private Long sectionId;

        LearningRecordInfo(LearningRecord learningRecord) {
            this.id = learningRecord.getId();
            this.finished = learningRecord.getFinished();
            this.moment = learningRecord.getMoment();
            this.lessonId = learningRecord.getLessonId();
            this.sectionId = learningRecord.getSectionId();
        }
    }

}
